package com.wpen.unit.service.job.impl;

import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.wpen.unit.core.ddo.JobRunningDo;
import com.wpen.unit.core.service.AgentScheduleHandler;
import com.wpen.unit.cvt.job.JobExec1LogCvt;
import com.wpen.unit.cvt.job.TaskExecLogCvt;
import com.wpen.unit.enums.ExecStatus;
import com.wpen.unit.enums.PlanType;
import com.wpen.unit.enums.YN;
import com.wpen.unit.exception.BizException;
import com.wpen.unit.infra.mybatis.job.po.AgentExec1LogPo;
import com.wpen.unit.infra.mybatis.job.po.AgentRegistryPo;
import com.wpen.unit.infra.mybatis.job.po.BatchExecLogPo;
import com.wpen.unit.infra.mybatis.job.po.JobExec1LogPo;
import com.wpen.unit.infra.mybatis.job.po.JobExec1RedologPo;
import com.wpen.unit.infra.mybatis.job.po.JobUndoPlanPo;
import com.wpen.unit.infra.mybatis.job.po.TaskExecLogPo;
import com.wpen.unit.infra.mybatis.job.po.TaskExecRedologPo;
import com.wpen.unit.infra.mybatis.job.po.TaskInfoPo;
import com.wpen.unit.infra.mybatis.job.po.TaskPlanPo;
import com.wpen.unit.infra.repository.job.AgentExec1LogRepository;
import com.wpen.unit.infra.repository.job.AgentRegistryRepository;
import com.wpen.unit.infra.repository.job.BatchExecLogRepository;
import com.wpen.unit.infra.repository.job.JobExec1LogRepository;
import com.wpen.unit.infra.repository.job.JobExec1RedologRepository;
import com.wpen.unit.infra.repository.job.JobUndoPlanRepository;
import com.wpen.unit.infra.repository.job.TaskExecLogRepository;
import com.wpen.unit.infra.repository.job.TaskExecRedologRepository;
import com.wpen.unit.infra.repository.job.TaskInfoRepository;
import com.wpen.unit.infra.repository.job.TaskPlanRepository;
import com.wpen.unit.service.job.RedoExecLogService;
import com.wpen.unit.utils.IdUtil;
import com.wpen.unit.web.dto.ContextResponse;
import com.wpen.unit.web.dto.job.JobExec1RedoRequest;
import com.wpen.unit.web.dto.job.JobExec1RedoResponse;
import com.wpen.unit.web.dto.job.JobExec1StopRequest;
import com.wpen.unit.web.dto.job.JobExec1StopResponse;
import com.wpen.unit.web.dto.job.TaskExecRedoRequest;
import com.wpen.unit.web.dto.job.TaskExecRedoResponse;

/**
 * 重新执行1日志业务处理.
 * 
 * @author Wang Peng
 * @date 2022-12-06
 */
@Service
public class RedoExecLogServiceImpl implements RedoExecLogService {

	@Autowired
	private JobExec1LogRepository jobExec1LogRepository;
	@Autowired
	private JobExec1RedologRepository jobExec1RedologRepository;
	@Autowired
	private TaskInfoRepository taskInfoRepository;
	@Autowired
	private JobUndoPlanRepository jobUndoPlanRepository;
	@Autowired
	private TaskExecLogRepository taskExecLogRepository;
	@Autowired
	private BatchExecLogRepository batchExecLogRepository;
	@Autowired
	private TaskPlanRepository taskPlanRepository;
	@Autowired
	private TaskExecRedologRepository taskExecRedologRepository;
	@Autowired
	private AgentScheduleHandler agentScheduleHandler;
	@Autowired
	private AgentExec1LogRepository agentExec1LogRepository;
	@Autowired
	private AgentRegistryRepository agentRegistryRepository;

	@Override
	@Transactional
	public JobExec1StopResponse stopJobExec1(JobExec1StopRequest jobExec1StopRequest) {
		Long jobExecLogId = jobExec1StopRequest.getJobLogId();
		// 查询数据是否存在
		JobExec1LogPo jobExec1LogPo = jobExec1LogRepository.queryById(jobExecLogId);
		if (jobExec1LogPo == null) {
			throw new BizException("E00001", "JobExec1Log:" + jobExecLogId);
		}
		if (!ExecStatus.Running.value().equals(jobExec1LogPo.getExecStatus())) {
			throw new BizException("E02001");
		}
		AgentExec1LogPo agentExec1LogPo = agentExec1LogRepository.queryByJobId(jobExecLogId,
				jobExec1LogPo.getTaskTriggerTime());
		String errorMsg = "";
		int exitCode = 1;
		if (agentExec1LogPo != null) {
			AgentRegistryPo agentPo = agentRegistryRepository.queryByIpv4(agentExec1LogPo.getAgentIpv4());
			JobRunningDo jobRunningDo = new JobRunningDo();
			//
			jobRunningDo.setBizCode(jobExec1LogPo.getBizCode());
			jobRunningDo.setBatchCode(jobExec1LogPo.getBatchCode());
			jobRunningDo.setTaskCode(jobExec1LogPo.getTaskCode());
			jobRunningDo.setAcctDate(agentExec1LogPo.getExecDate());
			jobRunningDo.setAppJarName(agentExec1LogPo.getAppJarName());
			//
			jobRunningDo.setJobLogId(jobExecLogId);
			jobRunningDo.setTaskLogId(jobExec1LogPo.getTaskExecLogId());
			jobRunningDo.setAgentId(agentExec1LogPo.getId());
			jobRunningDo.setIpv4(agentExec1LogPo.getAgentIpv4());
			jobRunningDo.setAppMode(agentExec1LogPo.getAppMode());
			jobRunningDo.setJobTriggerTime(jobExec1LogPo.getTaskTriggerTime());
			try {
				ContextResponse response = agentScheduleHandler.http2Kill(agentPo, jobRunningDo);
				errorMsg = response.getCode() + "-" + response.getMsg();
				exitCode = response.getExitValue();
			} catch (Exception e) {
				// 网络异常，直接失败吧。
				if (e instanceof SocketTimeoutException || e.getCause() instanceof SocketTimeoutException) {
					errorMsg = "用户终止：执行器连接错误";
				}
			}
			AgentExec1LogPo upAgentExec1LogPo = new AgentExec1LogPo();
			upAgentExec1LogPo.setId(agentExec1LogPo.getId());
			upAgentExec1LogPo.setExecStatus(ExecStatus.Excption.value());
			upAgentExec1LogPo.setExecResult(errorMsg);
			upAgentExec1LogPo.setEndTime(new Date());
			agentExec1LogRepository.updateById(upAgentExec1LogPo);

			JobUndoPlanPo upUndoPlanPo = new JobUndoPlanPo();
			upUndoPlanPo.setId(jobExecLogId);
			jobUndoPlanRepository.deleteByIds(new String[] { jobExecLogId.toString() });

			JobExec1LogPo upJobExec1LogPo = new JobExec1LogPo();
			upJobExec1LogPo.setId(jobExec1LogPo.getId());
			upJobExec1LogPo.setExecStatus(ExecStatus.Excption.value());
			upJobExec1LogPo.setExecResult(errorMsg);
			upJobExec1LogPo.setExitCode(exitCode);
			upJobExec1LogPo.setEndTime(new Date());
			jobExec1LogRepository.updateById(upJobExec1LogPo);
		}
		return new JobExec1StopResponse();
	}

	@Override
	@Transactional
	public JobExec1RedoResponse redoJobExec1(JobExec1RedoRequest jobExec1RedoRequest) {
		// 持久化操作
		Long jobExecLogId = jobExec1RedoRequest.getJobLogId();
		// 查询数据是否存在
		JobExec1LogPo jobExec1LogPo = jobExec1LogRepository.queryById(jobExecLogId);
		if (jobExec1LogPo == null) {
			throw new BizException("E00001", "JobExec1Log:" + jobExecLogId);
		}
		if (!ExecStatus.Finished.value().equals(jobExec1LogPo.getExecStatus())
				&& !ExecStatus.Excption.value().equals(jobExec1LogPo.getExecStatus())) {
			throw new BizException("E02001");
		}
		// 验证task的执行状态，如果是成功，改回执行中
		Long taskLogId = jobExec1LogPo.getTaskExecLogId();
		TaskExecLogPo taskExecLogPo = taskExecLogRepository.queryById(taskLogId);
		if (taskExecLogPo == null) {
			throw new BizException("E00001", "TaskExecLogId:" + taskLogId);
		}
		TaskExecLogPo upTaskExecLogPo = null;
		if (ExecStatus.Finished.value().equals(taskExecLogPo.getExecStatus())) {
			upTaskExecLogPo = taskExecLogPo.clone();
			upTaskExecLogPo.setExecStatus(ExecStatus.Running.value());
			upTaskExecLogPo.setEndTime(null);
		}
		// 验证batch状态
		Long batchLogId = jobExec1LogPo.getBatchExecLogId();
		BatchExecLogPo batchExecLogPo = batchExecLogRepository.queryById(batchLogId);
		BatchExecLogPo upbBatchExecLogPo = null;
		if (ExecStatus.Finished.value().equals(batchExecLogPo.getExecStatus())) {
			upbBatchExecLogPo = batchExecLogPo.clone();
			upbBatchExecLogPo.setExecStatus(ExecStatus.Running.value());
			upbBatchExecLogPo.setEndTime(null);
		}

		// 更新数据
		// 将joblog表数据复制到job redo表
		JobExec1RedologPo jobExec1RedologPo = JobExec1LogCvt.INSTANCE.jobLog2RedoLog(jobExec1LogPo);
		jobExec1RedologPo.setId(IdUtil.nextId());
		jobExec1RedologPo.setJobLogId(jobExecLogId);

		// 重新定义个触发时间
		long triggerTime = System.currentTimeMillis();
		// jobExec1LogPo 表更新回执行前
		jobExec1LogPo.setExecStatus(ExecStatus.Init.value());
		jobExec1LogPo.setTaskTriggerTime(triggerTime);
		jobExec1LogPo.setExitCode(null);
		jobExec1LogPo.setExecResult(null);
		jobExec1LogPo.setExecResultDetailed(null);
		jobExec1LogPo.setEndTime(null);
		// jobExec1LogPo.setStartupTime(new Date());

		String bizCode = jobExec1LogPo.getBizCode();
		String batchCode = jobExec1LogPo.getBatchCode();
		String taskCode = jobExec1LogPo.getTaskCode();
		TaskInfoPo taskInfoPo = taskInfoRepository.queryByCode(bizCode, batchCode, taskCode);

		JobUndoPlanPo jobUndoPlanPo = new JobUndoPlanPo();
		jobUndoPlanPo.setId(jobExecLogId);
		jobUndoPlanPo.setAppMode(taskInfoPo.getAppMode());
		jobUndoPlanPo.setAppJarName(taskInfoPo.getAppJarName());
		jobUndoPlanPo.setJobTriggerTime(triggerTime);
		jobUndoPlanPo.setExecStatus(ExecStatus.Init.value());
		jobUndoPlanPo.setCreateTime(new Date());

		// 增加扫描检测
		TaskPlanPo taskPlanPo = new TaskPlanPo();
		taskPlanPo.setId(IdUtil.nextId());
		taskPlanPo.setBatchExecLogId(batchLogId);
		taskPlanPo.setBizCode(taskExecLogPo.getBizCode());
		taskPlanPo.setBatchCode(taskExecLogPo.getBatchCode());
		taskPlanPo.setTaskCode(taskExecLogPo.getTaskCode());
		taskPlanPo.setPlanType(PlanType.Manual.value());
		taskPlanPo.setBatchTriggerTime(taskExecLogPo.getBatchTriggerTime());
		taskPlanPo.setTriggerNextTime(triggerTime);
		taskPlanPo.setValidStatus(YN.No.value());
		taskPlanPo.setCreateTime(new Date());
		taskPlanPo.setExecDate(taskExecLogPo.getExecDate());

		jobUndoPlanRepository.insert(jobUndoPlanPo);
		jobExec1LogRepository.updateByIdWithNull(jobExec1LogPo);
		jobExec1RedologRepository.insert(jobExec1RedologPo);
		taskPlanRepository.insert(taskPlanPo);
		if (upTaskExecLogPo != null) {
			taskExecLogRepository.updateByIdWithNull(upTaskExecLogPo);
		}
		if (upbBatchExecLogPo != null) {
			batchExecLogRepository.updateByIdWithNull(upbBatchExecLogPo);
		}

		// 返回响应信息
		JobExec1RedoResponse jobExec1RedologModResponse = new JobExec1RedoResponse();
		return jobExec1RedologModResponse;
	}

	@Override
	@Transactional
	public TaskExecRedoResponse redoTaskExeclog(TaskExecRedoRequest taskExecRedoRequest) {
		// 验证task的执行状态，如果是成功，改回执行中
		Long taskLogId = taskExecRedoRequest.getTaskLogId();
		TaskExecLogPo taskExecLogPo = taskExecLogRepository.queryById(taskLogId);
		if (taskExecLogPo == null) {
			throw new BizException("E00001", "TaskExecLogId:" + taskLogId);
		}
		if (!ExecStatus.Finished.value().equals(taskExecLogPo.getExecStatus())
				&& !ExecStatus.Excption.value().equals(taskExecLogPo.getExecStatus())) {
			throw new BizException("E02001");
		}

		// 验证batch状态
		Long batchLogId = taskExecLogPo.getBatchExecLogId();
		BatchExecLogPo batchExecLogPo = batchExecLogRepository.queryById(batchLogId);
		BatchExecLogPo upbBatchExecLogPo = null;
		if (ExecStatus.Finished.value().equals(batchExecLogPo.getExecStatus())) {
			upbBatchExecLogPo = batchExecLogPo.clone();
			upbBatchExecLogPo.setExecStatus(ExecStatus.Running.value());
			upbBatchExecLogPo.setEndTime(null);
		}

		List<TaskExecLogPo> taskExecLogPos = taskExecLogRepository.queryListByBatchId(batchLogId,
				taskExecLogPo.getBatchTriggerTime(), taskExecLogPo.getBizCode(), taskExecLogPo.getBatchCode(),
				taskExecLogPo.getTaskCode());
		List<Long> taskLogIds = new ArrayList<>();
		for (TaskExecLogPo taskExecLogPo2 : taskExecLogPos) {
			taskLogIds.add(taskExecLogPo2.getId());
		}
		// 查询job
		List<JobExec1LogPo> jobExec1LogPos = jobExec1LogRepository.queryListByBatchId(batchLogId, taskLogIds);

		TaskExecRedologPo taskExecRedologPo = TaskExecLogCvt.INSTANCE.queryDo2RodeDo(taskExecLogPo);
		taskExecRedologPo.setId(IdUtil.nextId());
		taskExecRedologPo.setTaskLogId(taskExecLogPo.getId());

		List<JobExec1RedologPo> jobExec1RedologPos = new ArrayList<>();
		List<Long> jobLogIds = new ArrayList<>();
		if (jobExec1LogPos != null) {
			for (JobExec1LogPo jobExec1LogPo : jobExec1LogPos) {
				JobExec1RedologPo jobExec1RedologPo = JobExec1LogCvt.INSTANCE.jobLog2RedoLog(jobExec1LogPo);
				jobExec1RedologPo.setId(IdUtil.nextId());
				jobExec1RedologPo.setJobLogId(jobExec1LogPo.getId());
				jobExec1RedologPos.add(jobExec1RedologPo);
				jobLogIds.add(jobExec1LogPo.getId());
			}
		}

		// 重新定义个触发时间
		long triggerTime = System.currentTimeMillis();

//		taskExecLogPo.setExecStatus(ExecStatus.Running.value());
//		taskExecLogPo.setTaskTriggerTime(triggerTime);
//		taskExecLogPo.setEndTime(null);

		// 增加扫描检测
		TaskPlanPo taskPlanPo = new TaskPlanPo();
		taskPlanPo.setId(IdUtil.nextId());
		taskPlanPo.setBatchExecLogId(batchLogId);
		taskPlanPo.setBizCode(taskExecLogPo.getBizCode());
		taskPlanPo.setBatchCode(taskExecLogPo.getBatchCode());
		taskPlanPo.setTaskCode(taskExecLogPo.getTaskCode());
		taskPlanPo.setPlanType(PlanType.Manual.value());
		taskPlanPo.setBatchTriggerTime(taskExecLogPo.getBatchTriggerTime());
		taskPlanPo.setTriggerNextTime(triggerTime);
		taskPlanPo.setValidStatus(YN.Yes.value());
		taskPlanPo.setCreateTime(new Date());
		taskPlanPo.setExecDate(taskExecLogPo.getExecDate());

		taskExecRedologRepository.insert(taskExecRedologPo);
		taskExecLogRepository.deleteByBatchLogIdAndCodes(batchLogId, taskExecLogPo.getBatchTriggerTime(),
				taskExecLogPo.getBizCode(), taskExecLogPo.getBatchCode(), taskExecLogPo.getTaskCode());
		taskPlanRepository.insert(taskPlanPo);
		jobExec1RedologRepository.insertBatch(jobExec1RedologPos);
		if (jobLogIds != null && !jobLogIds.isEmpty()) {
			Long[] jobIds = new Long[jobExec1LogPos.size()];
			jobIds = jobLogIds.toArray(jobIds);
			jobExec1LogRepository.deleteByIds(jobIds);
		}

		if (upbBatchExecLogPo != null) {
			batchExecLogRepository.updateByIdWithNull(upbBatchExecLogPo);
		}

		// 返回响应信息
		TaskExecRedoResponse taskExecRedologModResponse = new TaskExecRedoResponse();
		return taskExecRedologModResponse;
	}

}
